/*
 * Saphre - Suffix Arrays for Phrase Extraction
 * Copyright (C) 2013 
 * Dale Gerdemann - Tübingen, Germany 
 * Niko Schenk - Frankfurt am Main, Germany
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package saphre.commands;

import collectors.impl.GappyPhrasesInitialPartPrintCollector;
import collectors.impl.RepeatsByThresholdCollector;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import saphre.core.SaphreBase;
import collectors.impl.visitors.CollectTraversal4;
import util.Interval;
import saphre.core.Store;
import saphre.core.SuffixArray;
import util.statistics.Ngram;
import util.sedgewick.Stopwatch;
import collectors.impl.visitors.CollectTraversal;

/**
 * A class to extract discontinuous phrases.
 *
 * Here is a simple example generated from Lewis Carroll / Alice in Wonderland,
 * Through the Looking Glass:
 *
 * {(alice.txt,22),(through_looking_glass.txt,21)} df:2 tf:43 in a
 *
 * [careless|coaxing|deep hollow|discontented|fretful|friendly|frightened|
 * kinder|louder|low hurried|melancholy|more subdued|mournful|piteous|pitying|
 * plaintive|pleased|rather complaining|rather offended|rather severe|
 * severe|slow thoughtful|solemn|sorrowful|sulky|surprised|thoughtful|
 * triumphant|very decided|very hopeful|very humble|very respectful|wondering]
 *
 * tone
 *
 * The example shows a left part (context) 'in a', a number of fillers (bridge)
 * including mostly adjectives, and a right part (context) 'tone'.
 *
 * @author Niko Schenk
 * Algorithms and initial implementation by Dale Gerdemann.
 */
public class CmdGappy {

    private CmdGappyParameters gappyParameters = new CmdGappyParameters();
    
    
    /**
     * Extract gappy phrases with default parameters.
     * 
     * @param store
     * @param pa
     * @param top
     * @param sa 
     */
    public void executeCommandGappy(Store store, SuffixArray pa, Interval top, SuffixArray sa) {
        extractGappyPhrases(store, pa, top, sa, 
                gappyParameters);
    }
    
    
    /**
     * Extract gappy phrases with a matcher object for the parameters.
     *
     * @param store
     * @param sa
     * @param pa
     * @param top
     * @param m
     */
    public void executeCommandGappy(Store store, SuffixArray pa, Interval top, SuffixArray sa, Matcher m) {
        // Get user input.
        getUserSpecificParameters(m);
        
        // Extract them.
        extractGappyPhrases(store, pa, top, sa, gappyParameters);
    }

    /**
     * Extract gappy phrases.
     *
     */
    public void executeCommandGappy(SaphreBase sb,
            CmdGappyParameters gappyParameters) {
        extractGappyPhrases(sb.getStore(), sb.getSa().prefixArray(), sb.getTop(), sb.getSa(), gappyParameters);
    }
    
    /**
     * Extract gappy phrases with all parameters explicitly specified.
     *
     */
    public void executeCommandGappy(Store store, SuffixArray pa, Interval top, SuffixArray sa,
            CmdGappyParameters gappyParameters) {
        extractGappyPhrases(store, pa, top, sa, gappyParameters);
    }
    
    
    

    /*
     * Extract gappy phrases and do the actual traversal.
     */
    private void extractGappyPhrases(Store store, SuffixArray pa, Interval top, SuffixArray sa,
            CmdGappyParameters gappyParameters) {

       
        
        PrintWriter w = null;
        //try {
        //    w = new PrintWriter(new File("ngrams.txt"));
        //} catch (FileNotFoundException ex) {
        //    Logger.getLogger(CmdGappy.class.getName()).log(Level.SEVERE, null, ex);
        //}
        
        
        // Preprocess ngrams and compute tf and df only once for every ngram.
        // This way, speed up the whole process.
        System.out.println("Getting repeats...");
        Stopwatch swRepeats = new Stopwatch();
        RepeatsByThresholdCollector repeatsCollector = new RepeatsByThresholdCollector(store, sa, w, 0, 5, 1, "", 0, 1);
        CollectTraversal repeats = new CollectTraversal(store, sa, repeatsCollector, top);
        repeats.traverse();
        System.out.println("...done."+ swRepeats.elapsedTime());
        //w.flush(); w.close();
        
        // Idea: Precompute term frequencies of fillers and store them in a map.
        Map<String, Ngram> ngramMap = repeatsCollector.getNgramMap();
        
        System.out.println("\nNumber of precompted ngrams: " + ngramMap.size() + "\n");
        
        Stopwatch sw = new Stopwatch();
        
        // Recursive collectors.
        PrintWriter gW = null;
        if(gappyParameters.isWriteToFile()) {
            try {
                gW = new PrintWriter(new File("gappy_phrases.txt"));
            } catch (FileNotFoundException ex) {
                Logger.getLogger(CmdGappy.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        GappyPhrasesInitialPartPrintCollector gappyCollector =
                new GappyPhrasesInitialPartPrintCollector(store, pa, top, sa, 
                gappyParameters, ngramMap, gW);
        
        
        CollectTraversal4 gappys =
                new CollectTraversal4(store, pa, gappyCollector, top);
        gappys.traverse();
        
        System.out.println("Gappy phrase collection took: " +sw.elapsedTime());
    }
    

    /*
     * Get the parameter values that the user specified.
     */
    private void getUserSpecificParameters(Matcher m) {
        // Get parameters.
        gappyParameters = new CmdGappyParameters();
        // Get values and overwrite default ones by user defined values.
        
        // ** EVERYTHING COMBINED ** //
        // Min gap size.
        if (m.group(1) != null) {
            int minGap = Integer.parseInt(m.group(2));
            gappyParameters.setMinGap(minGap);
        }
        // Max gap size.
        if (m.group(3) != null) {
            int maxGap = Integer.parseInt(m.group(4));
            gappyParameters.setMaxGap(maxGap);
        }
        // Min mutual information of left and right part combined.
        if (m.group(5) != null) {
            double minMiLeftRightPart = Double.parseDouble(m.group(6));
            gappyParameters.setMinMiLeftRightPart(minMiLeftRightPart);
        }
        // Min combined average mi Y&C
        if (m.group(8) != null) {
            double minCombinedAverageMiYamamotoChurch = Double.parseDouble(m.group(9));
            gappyParameters.setMinCombinedAverageMiYamamotoChurch(minCombinedAverageMiYamamotoChurch);
        }
        // Min global ridf of gappy phrase.
        if (m.group(11) != null) {
            double minGlobalRidf = Double.parseDouble(m.group(12));
            gappyParameters.setMinGlobalRidf(minGlobalRidf);
        }
         // Min term frequency of gappy phrase
        if (m.group(14) != null) {
            int minTfOfGappyPhrase = Integer.parseInt(m.group(15));
            gappyParameters.setMinTfOfGappyPhrase(minTfOfGappyPhrase);
        }
        // Min document frequency of gappy phrase
        if (m.group(16) != null) {
            int minDfOfGappyPhrase = Integer.parseInt(m.group(17));
            gappyParameters.setMinDfOfGappyPhrase(minDfOfGappyPhrase);
        }


        // ** LEFT PART ** //
        // Min length of left part
        if (m.group(18) != null) {
            int minLengthOfLeftPart = Integer.parseInt(m.group(19));
            gappyParameters.setMinLengthOfLeftPart(minLengthOfLeftPart);
        }
        // Max length of left part
        if (m.group(20) != null) {
            int maxLengthOfLeftPart = Integer.parseInt(m.group(21));
            gappyParameters.setMaxLengthOfLeftPart(maxLengthOfLeftPart);
        }
        // Min overall term frequency of left part in corpus
        if (m.group(22) != null) {
            int minTfOfLeftPartInCorpus = Integer.parseInt(m.group(23));
            gappyParameters.setMinTfOfLeftPartInCorpus(minTfOfLeftPartInCorpus);
        }
        // Max overall term frequency of left part in corpus
        if (m.group(24) != null) {
            int maxTfOfLeftPartInCorpus = Integer.parseInt(m.group(25));
            gappyParameters.setMaxTfOfLeftPartInCorpus(maxTfOfLeftPartInCorpus);
        }
        // Min residual inverse document frequency of left part in corpus
        if (m.group(26) != null) {
            double minRidfOfLeftPartInCorpus = Double.parseDouble(m.group(27));
            gappyParameters.setMinRidfOfLeftPartInCorpus(minRidfOfLeftPartInCorpus);
        }
        // Substring contained within left part
        if (m.group(29) != null) {
            // Remove quotes.
            String inLeftPart = m.group(30).toString().substring(1, m.group(30).toString().length()-1);
            gappyParameters.setInLeftPart(inLeftPart);
        }


        // ** RIGHT PART ** //
        // Min length of right part
        if (m.group(31) != null) {
            int minLengthOfRightPart = Integer.parseInt(m.group(32));
            gappyParameters.setMinLengthOfRightPart(minLengthOfRightPart);
        }
        // Max length of right part
        if (m.group(33) != null) {
            int maxLengthOfRightPart = Integer.parseInt(m.group(34));
            gappyParameters.setMaxLengthOfRightPart(maxLengthOfRightPart);
        }
        // Min overall term frequency of right part in corpus
        if (m.group(35) != null) {
            int minTfOfRightPartInCorpus = Integer.parseInt(m.group(36));
            gappyParameters.setMinTfOfRightPartInCorpus(minTfOfRightPartInCorpus);
        }
        // Max overall term frequency of right part in corpus
        if (m.group(37) != null) {
            int maxTfOfRightPartInCorpus = Integer.parseInt(m.group(38));
            gappyParameters.setMaxTfOfRightPartInCorpus(maxTfOfRightPartInCorpus);
        }
        // Min residual inverse document frequency of right part in corpus
        if (m.group(39) != null) {
            double minRidfOfRightPartInCorpus = Double.parseDouble(m.group(40));
            gappyParameters.setMinRidfOfRightPartInCorpus(minRidfOfRightPartInCorpus);
        }
        // Substring contained within right part
        if (m.group(42) != null) {
            String inRightPart = m.group(43).toString().substring(1, m.group(43).toString().length()-1);
            gappyParameters.setInRightPart(inRightPart);
        }


        // ** FILLERS ** //
        // Min number of fillers
        if (m.group(44) != null) {
            int minNumberOfFillers = Integer.parseInt(m.group(45));
            gappyParameters.setMinNumberOfFillers(minNumberOfFillers);
        }
        // Min sum of term frequencies of fillers.
        if (m.group(46) != null) {
            int minSumTfOfFillers = Integer.parseInt(m.group(47));
            gappyParameters.setMinSumTfOfFillers(minSumTfOfFillers);
        }
        // Min average residual inverse document frequency of all fillers
        if (m.group(48) != null) {
            double minAverageRidfOfFillers = Double.parseDouble(m.group(49));
            gappyParameters.setMinAverageRidfOfFillers(minAverageRidfOfFillers);
        }
        // Min proportion of maximal fillers between left and right part.
        if (m.group(51) != null) {
            double minMaxfill = Double.parseDouble(m.group(52));
            gappyParameters.setMinMaxfill(minMaxfill);
        }
        // Ratio.
        if (m.group(54) != null) {
            int minRatio = Integer.parseInt(m.group(55));
            gappyParameters.setMinRatio(minRatio);
        }
        // Substring contained within one of the fillers.
        if (m.group(56) != null) {
            String inOneOfFillers = m.group(57).toString().substring(1, m.group(57).toString().length()-1);
            gappyParameters.setInOneOfFillers(inOneOfFillers);
        }


        // ** PRINT OPTIONS ** //
        // Write to file.
        if (m.group(58) != null) {
            boolean writeToFile = Boolean.parseBoolean(m.group(59));
            gappyParameters.setWriteToFile(writeToFile);
        }
        // Write to console (standard output stream).
        if (m.group(60) != null) {
            boolean printToConsole = Boolean.parseBoolean(m.group(61));
            gappyParameters.setPrintToConsole(printToConsole);
        }
    }
}